# Echo client program
import socket
import select
from threading import Thread
import sys
import time
import traceback
import Queue
import Tkinter

#from ttrModuleLoad import *
import ttrConst 
reload(ttrConst)
from ttrConst import *

import ttrWidget
reload(ttrWidget)
from ttrWidget import msg_table

import pdb

class client:
    def __init__(self, ip_addr):
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.status = ClientStt['trying']
        self.buf = ''
        self.timeout = time.time() + HEART_BEAT_TIME
        self.msg_queue = Queue.Queue() # from user input
        self.txt_queue = Queue.Queue() # to be displayed
        self.root = None
        try:
            self.s.connect((ip_addr, GAME_PORT))
        except:
            print 'fail to connect'
            self.status = ClientStt['fail']
        else:
            self.run()
        
    def run(self):
        self.status = ClientStt['connected']
        self.s.setblocking(0)
        
        # start receiving thread
        RxThread = Thread(target=self.TxRxProc)
        RxThread.setDaemon(True)
        RxThread.start()
        
        GUI_thread = Thread(target=self.GUI_Proc, args=(self.msg_queue, self.txt_queue,))
        GUI_thread.setDaemon(True)
        GUI_thread.start()
                
    def toServer(self, header, info):
        msg = header + info + TERMINATOR
        try:
            self.s.send(fmtX %len(msg) + msg)
        except:
            self.status = ClientStt['lost'] 
            print 'connect lost'
        
    def chkHeartbeat(self):
        if time.time() > self.timeout:
            #send heartbeat
            self.timeout = time.time() + HEART_BEAT_TIME
            self.toServer(cmd_table['heart'],'')
            
    def chkGUI(self):
        # main user input
        if not self.msg_queue.empty():
            msg = self.msg_queue.get().strip()
            self.toServer(cmd_table['info'], msg)
            if msg == 'exit':
                self.status = ClientStt['exit']
             
    def chkServer(self):
        # distribute server information
        ready = select.select([self.s], [], [], 0.1)
        if ready[0]:
            try:
                self.buf += self.s.recv(10)
            except:
                self.status = ClientStt['lost']
                
            if len(self.buf)>HEAD_NUMBER_SIZE and len(self.buf[HEAD_NUMBER_SIZE:]) >= int(self.buf[:HEAD_NUMBER_SIZE],16):
                # completion message, maybe more
                #print len(buf), int(buf[:HEAD_NUMBER_SIZE],16), len(buf[HEAD_NUMBER_SIZE:])
                
                data = self.buf
                data = data.split(TERMINATOR)
                self.buf = data[-1]
                #pdb.set_trace()
                for msg in data[:-1]: # display for the moment
                    command = msg[HEAD_NUMBER_SIZE:(HEAD_NUMBER_SIZE+MSG_HEAD)]
                    param = msg[HEAD_NUMBER_SIZE+MSG_HEAD:]
                    if command == cmd_table['seat']:  self.info.update(evel(param))
                    if command == cmd_table['heart']:  pass # print '.',
                    elif command == cmd_table['info']:
                        # to be displayed on Text window
                        self.txt_queue.put(param)
                    elif command == cmd_table['conf']:
                        print 'configure', eval(param)
                    
                    else:
                        print 'unknow cmd:', command, param
                
    def GUI_Proc(self, msg_queue, txt_queue):
        self.root = Tkinter.Tk()
        # msg_table polls msg_queue and txt_queue from root.after()
        self.msg_table = msg_table(self.root, msg_queue, txt_queue)
        self.root.mainloop()
    
    def TxRxProc(self):
        while self.status == ClientStt['connected']:
            # non block checking
            self.chkServer()
            self.chkHeartbeat()
            self.chkGUI()
        else:
            print 'TxRxProc stop', self.status

def main(ip_addr):
        
    try:
        c = client(ip_addr)
        print 'Server connected'
        # first message
        c.toServer(cmd_table['seat'], 'Seat?')
        while c.status == ClientStt['connected']:
            time.sleep(CLIENT_OFF_CHECK_SLEEP_TIME)
        else:
            print 'main client destroy'
            c.root.quit()
            c.s.close()
            print 'finish'
    except:
        traceback.print_exc()
        
        
            
if __name__ == '__main__':

    try:
        ip_addr = sys.argv[1]
    except IndexError:
        ip_addr = socket.gethostbyname_ex(socket.gethostname())[0]
        
    main(ip_addr)
    
    


